package rmi;

import java.io.Serializable;
import java.rmi.AccessException;
import java.rmi.AlreadyBoundException;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

public class UtilitairesRmi implements Remote, Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private static final int NUMERO_PORT = 8080;

	Registry rmiRegistry = null;

	private static UtilitairesRmi instance;

	public static UtilitairesRmi getInstance() throws RemoteException, NotBoundException, AlreadyBoundException {
		if (instance == null) {
			synchronized(UtilitairesRmi.class) {
				instance = obtenirUtilitairesRmi();
				if (instance == null) {
					instance = new UtilitairesRmi();
				}
			}
		}
		return instance;
	}
	
	public static UtilitairesRmi lookoutForRmiRegistry(String host)  {
		try {
			instance = (UtilitairesRmi)LocateRegistry.getRegistry(host, NUMERO_PORT).lookup(Constantes.NOM_UTILITAIRES_RMI);
		} catch (RemoteException | NotBoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			instance = null;
		}
		
		return instance;
	}

	private static UtilitairesRmi obtenirUtilitairesRmi () {
		UtilitairesRmi instanceUtilitairesRmi = null;
		try {
			instanceUtilitairesRmi = (UtilitairesRmi)LocateRegistry.getRegistry(NUMERO_PORT).lookup(Constantes.NOM_UTILITAIRES_RMI);
		} catch (RemoteException e) {
			System.out.println("Le registry au port " + NUMERO_PORT + " n'est pas créé, il sera donc créé");
		} catch (NotBoundException e) {
			System.out.println("Le registry au port " + NUMERO_PORT + " n'est pas créé, il sera donc créé");
		}
		
		return instanceUtilitairesRmi;
	}

	private UtilitairesRmi() throws RemoteException, AlreadyBoundException {
		rmiRegistry = LocateRegistry.createRegistry(NUMERO_PORT);
		rmiRegistry.bind(Constantes.NOM_UTILITAIRES_RMI, (Remote) this);
		System.out.println("RmiRegistry created");
	}

	//Objet global
	
	public void bind(String nom, Object object) throws AccessException, RemoteException, AlreadyBoundException {
		if (!verifierSiExisteDansRmi(nom)) {
			System.out.println("Object binded : " + nom);
			this.rmiRegistry.bind(nom, UnicastRemoteObject.exportObject((Remote) object, 0));
		}
	}
	
	public Object obtenirEtBind(String nom, Object object) throws AccessException, RemoteException, AlreadyBoundException, NotBoundException {
		this.bind(nom, object);
		return this.rmiRegistry.lookup(nom);
	}

	public Object obtenirEtBind(Object object) throws AccessException, RemoteException, AlreadyBoundException, NotBoundException {
		this.bind(object.toString(), object);

		return this.rmiRegistry.lookup(object.toString());
	}

//	public void bind(Object object) throws AccessException, RemoteException, AlreadyBoundException {
//		if (!verifierSiExisteDansRmi(object.toString())) {
//			this.rmiRegistry.bind(object.toString(), UnicastRemoteObject.exportObject((Remote) object, 0));
//			System.out.println("Object binded : " + object.toString());
//		}
//	}
	
	public void unbind(Object object) throws AccessException, RemoteException, NotBoundException {
		if (verifierSiExisteDansRmi(object.toString())) {
			this.rmiRegistry.unbind(object.toString());
		}
	}

	public Object obtenirObjet(String nom) {
		if (verifierSiExisteDansRmi(nom)) {
			try {
				return this.rmiRegistry.lookup(nom);
			} catch (RemoteException | NotBoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return null;
	}

	private boolean verifierSiExisteDansRmi(String nomObjet) {
		try {
			for (String objectRmi : this.rmiRegistry.list()) {
				if (objectRmi.equals(nomObjet)) {
					return true;
				}
			}
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return false;
	}

}
